<!DOCTYPE html>
<html>
<head>
    <title>Electromagnetic Field Diagram</title>
</head>
<body>

<canvas id="physicsCanvas" width="500" height="500"></canvas>

<script>
    const canvas = document.getElementById('physicsCanvas');
    const ctx = canvas.getContext('2d');

    // --- Configuration ---
    const origin = { x: 250, y: 360 };
    const scale = 70;
    const l_coord = 1.3;
    const z0_coord = 1.8;
    const particle_x = -2.0;
    const axis_len = 2.4;
    const font = 'italic 18px serif';
    const label_offset = 15;

    // --- Helper Functions ---

    /**
     * Projects 3D coordinates to 2D screen coordinates.
     * @param {number} x - The x-coordinate in 3D space.
     * @param {number} y - The y-coordinate in 3D space.
     * @param {number} z - The z-coordinate in 3D space.
     * @returns {{x: number, y: number}} - The 2D screen coordinates.
     */
    function project(x, y, z) {
        const angle = Math.PI / 6; // 30 degrees
        const sx = origin.x + scale * (y - x) * Math.cos(angle);
        const sy = origin.y + scale * (y + x) * Math.sin(angle) - scale * z;
        return { x: sx, y: sy };
    }

    /**
     * Draws an arrow from (x1, y1) to (x2, y2).
     * @param {number} x1 - Start x of the arrow line.
     * @param {number} y1 - Start y of the arrow line.
     * @param {number} x2 - End x of the arrow line (where the head is).
     * @param {number} y2 - End y of the arrow line (where the head is).
     * @param {number} size - The size of the arrowhead.
     */
    function drawArrow(x1, y1, x2, y2, size = 10) {
        const angle = Math.atan2(y2 - y1, x2 - x1);
        ctx.save();
        ctx.beginPath();
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.stroke();

        ctx.beginPath();
        ctx.moveTo(x2, y2);
        ctx.lineTo(x2 - size * Math.cos(angle - Math.PI / 8), y2 - size * Math.sin(angle - Math.PI / 8));
        ctx.stroke();
        
        ctx.beginPath();
        ctx.moveTo(x2, y2);
        ctx.lineTo(x2 - size * Math.cos(angle + Math.PI / 8), y2 - size * Math.sin(angle + Math.PI / 8));
        ctx.stroke();
        
        ctx.restore();
    }
    
    // --- Main Drawing Logic ---
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.strokeStyle = 'black';
    ctx.fillStyle = 'black';
    ctx.font = font;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.lineWidth = 2;

    // 1. Draw Axes
    const pOrigin = project(0, 0, 0);
    const pX = project(axis_len, 0, 0);
    const pY = project(0, axis_len, 0);
    const pZ = project(0, 0, axis_len);

    drawArrow(pOrigin.x, pOrigin.y, pX.x, pX.y);
    drawArrow(pOrigin.x, pOrigin.y, pY.x, pY.y);
    drawArrow(pOrigin.x, pOrigin.y, pZ.x, pZ.y);

    ctx.fillText('x', pX.x - label_offset, pX.y + label_offset / 2);
    ctx.fillText('y', pY.x + label_offset, pY.y + label_offset / 2);
    ctx.fillText('z', pZ.x + 5, pZ.y - label_offset);

    // 2. Draw the square loop
    ctx.save();
    ctx.lineWidth = 3;
    const h = l_coord / 2;
    const p1 = project(h, -h, 0);
    const p2 = project(h, h, 0);
    const p3 = project(-h, h, 0);
    const p4 = project(-h, -h, 0);

    ctx.beginPath();
    ctx.moveTo(p1.x, p1.y);
    ctx.lineTo(p2.x, p2.y);
    ctx.lineTo(p3.x, p3.y);
    ctx.lineTo(p4.x, p4.y);
    ctx.closePath();
    ctx.stroke();
    ctx.restore();

    // 3. Draw loop dimensions (l)
    // For x-dimension
    const dim_x_y = -h - 0.25;
    const x_start = project(-h, dim_x_y, 0);
    const x_mid = project(0, dim_x_y, 0);
    const x_end = project(h, dim_x_y, 0);
    drawArrow(x_mid.x, x_mid.y, x_start.x, x_start.y, 8);
    drawArrow(x_mid.x, x_mid.y, x_end.x, x_end.y, 8);
    const l_label_pos_x = project(0, dim_x_y - 0.1, 0);
    ctx.fillText('l', l_label_pos_x.x, l_label_pos_x.y);

    // For y-dimension
    const dim_y_x = h + 0.25;
    const y_start = project(dim_y_x, -h, 0);
    const y_mid = project(dim_y_x, 0, 0);
    const y_end = project(dim_y_x, h, 0);
    drawArrow(y_mid.x, y_mid.y, y_start.x, y_start.y, 8);
    drawArrow(y_mid.x, y_mid.y, y_end.x, y_end.y, 8);
    const l_label_pos_y = project(dim_y_x + 0.2, 0, 0);
    ctx.textAlign = 'left';
    ctx.fillText('l', l_label_pos_y.x, l_label_pos_y.y);
    ctx.textAlign = 'center';

    // 4. Draw particle and its path
    const p_particle = project(particle_x, 0, z0_coord);
    const p_on_z_axis = project(0, 0, z0_coord);

    // Dashed line
    ctx.save();
    ctx.setLineDash([5, 5]);
    ctx.beginPath();
    ctx.moveTo(p_particle.x, p_particle.y);
    ctx.lineTo(p_on_z_axis.x, p_on_z_axis.y);
    ctx.stroke();
    ctx.restore();
    
    // Particle charge q
    ctx.beginPath();
    ctx.arc(p_particle.x, p_particle.y, 4, 0, 2 * Math.PI);
    ctx.fill();
    ctx.fillText('q', p_particle.x - label_offset, p_particle.y + 5);

    // Velocity vector v (pointing in +x direction)
    const v_len = 1.0;
    const p_v_start = project(particle_x, 0, z0_coord);
    const p_v_tip = project(particle_x + v_len, 0, z0_coord);
    drawArrow(p_v_start.x, p_v_start.y, p_v_tip.x, p_v_tip.y, 10);
    const p_v_label = project(particle_x - 0.5, 0, z0_coord);
    ctx.fillText('v', p_v_label.x, p_v_label.y - 10);

    // 5. Draw z0 indicator
    ctx.beginPath();
    ctx.moveTo(pOrigin.x, pOrigin.y);
    ctx.lineTo(p_on_z_axis.x, p_on_z_axis.y);
    ctx.stroke();
    // T-bars
    ctx.beginPath();
    ctx.moveTo(pOrigin.x - 7, pOrigin.y);
    ctx.lineTo(pOrigin.x + 7, pOrigin.y);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(p_on_z_axis.x - 7, p_on_z_axis.y);
    ctx.lineTo(p_on_z_axis.x + 7, p_on_z_axis.y);
    ctx.stroke();
    ctx.textAlign = 'left';
    ctx.fillText('z', p_on_z_axis.x + 10, p_on_z_axis.y + (pOrigin.y - p_on_z_axis.y)/2);
    ctx.font = 'italic 14px serif';
    ctx.fillText('0', p_on_z_axis.x + 17, p_on_z_axis.y + (pOrigin.y - p_on_z_axis.y)/2 + 6);
    ctx.font = font;
    ctx.textAlign = 'center';

    // 6. Draw Caption
    ctx.font = 'bold 16px serif';
    ctx.fillText('Fig. 2.43', canvas.width / 2, canvas.height - 30);

</script>

</body>
</html>